home *** CD-ROM | disk | FTP | other *** search
/ The Best of MacTutor - S…e Code for Volumes 1 to 5 / The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin / Source Code / #21 (Jun 87) / Corrected format Source Files / SCSI.a < prev   
Text File  |  1987-06-01  |  25KB  |  812 lines

  1. ;*********************** File: SCSI.a *************************
  2. ;**************************************************************
  3. ;
  4. ; This file contains all the items in the SCSI menu.  It also
  5. ; contains the SCSI primatives for comunication with SCSI hard 
  6. ; disks.  
  7. ;
  8. ; Note: All the symbols that are declared or imported before 
  9. ; start of the first module (PROC, MAIN or RECORD) are defined
  10. ; for all modules in this file.  Forward references to other
  11. ; modules in a file must be imported. 
  12.  
  13.     INCLUDE        'FormatEqu.a'
  14.     LOAD        'Traps.d'
  15.     LOAD        'ToolEqu.d'
  16.     LOAD        'SysEqu.d'
  17.     LOAD        'QuickEqu.d'
  18.     LOAD        'SCSIEqu.d'
  19.  
  20.     EXPORT    (Res,Last_Cmd,CompStat,CompMsg):DATA
  21.     EXPORT    (BadB_Num):DATA
  22.     
  23. Addr        ds.w    1    ;address of hard disk
  24. Heads        ds.l    1    ;number of heads on hard disk
  25. Cyls        ds.l    1    ;number of cylinders on hard disk
  26. WrtPreComp    ds.l    1    ;cylinder to start write precompensation
  27. RedWrtCur    ds.l    1    ;cylinder to start reduced write current
  28. Interleave    ds.w    1    ;interleave number to be used
  29. StepCode    ds.w    1    ;type of step pulse used
  30.     
  31. CompStat    ds.w    1    ;status from _SCSIComplete
  32. CompMsg        ds.w    1    ;message from _SCSIComplete
  33.     
  34. Res            ds.w    1    ;result from SCSI commands    
  35. Last_Cmd    ds.w    1    ;last command executed
  36.  
  37. BadB_Num    ds.l    1                ;total number of bad blocks
  38.     IMPORT    (DialogPort,ItemType,ItemHandle,ItemRect):DATA
  39.     IMPORT    (EventLoop,DefButton,RadioHiLite):CODE
  40.     IMPORT    (CountOff,ExtractNumb,SortBuff,OutBuff):CODE
  41.     IMPORT    (ErrorProc,ClearBuff):CODE
  42.     IMPORT    (DialogBuff,ButtonHit):DATA
  43.     IMPORT    (StrBuff1,StrBuff2,StrBuff3,StrBuff4):DATA
  44.     
  45. Buffers        RECORD    EXPORT
  46.     EXPORT    (CommandBuff,PseudoProg,ParamBuff):DATA
  47.     EXPORT    (BadB_List,BadB_Out):DATA
  48.     ALIGN    2
  49.     
  50. CommandBuff    ds.b    CBuffLen        ;buffer for SCSI commands
  51. PseudoProg    ds.b    PProgLen        ;buffer for pseudo program
  52. ParamBuff    ds.b    ParamBuffLen    ;buffer for parameters
  53. BadB_List    ds.l    MaxBBListLen    ;buffer area for entering and 
  54.                                         ;sorting bad blocks
  55. BadB_Out    ds.l    MaxBBOutLen        ;buffer area for output to
  56.                                         ;to the disk drive
  57.  
  58.     ENDR
  59.     
  60. ; PROC    SelAddrProc
  61. ;
  62. ; This procedure gets the address of the device to be formatted
  63. ; from the user. It then tests to see if the device is connected
  64. ; and if the device is ready to be formatted. If either of these
  65. ; are false, it jumps to ErrorProc (error handling procedure).
  66.  
  67. SelAddrProc    PROC    EXPORT
  68.     IMPORT    (Hd_Select,HD_TestUnit,HD_Discon):CODE
  69.     IMPORT    (UnHiLite,ResetDisk):CODE
  70.     
  71.     clr.l    -(A7)                ;space for pointer to dialog
  72.     move.w    #SelAddrRN,-(A7)    ;select address dialog resource#
  73.     pea        DialogBuff(A5)        ;push pointer to dialog storage
  74.     move.l    #-1,-(A7)            ;make dialog top most window
  75.     _GetNewDialog
  76.     
  77.     move.l    (A7),DialogPort(A5)    ;save pointer to dialog and 
  78.                                     ;leave a copy on the stack  the
  79.                                     ;for call to _SetPort
  80.     _SetPort
  81.     lea        DialogBuff(A5),A4    ;pass address of dialog record
  82.     jsr        DefButton            ;make default = "Select" button
  83.     
  84.     move.w    #10,D0                ;make Mac's address grey
  85.     jsr        UnHiLite
  86.     
  87. ; Register ussage:
  88. ;    D0    Radio button that was selected, now must be unselected
  89. ;    D1    Radio button that was just clicked on; to be selected
  90.  
  91. ; Initialize D0 and D3 for first call to RadioHiLite.  D0=0 
  92. ; is flag for no radio button to deselect.  D1=3 is to set the
  93. ; default SCSI address = 0.
  94.     clr.l    D0
  95.     moveq.l    #3,D7                
  96.      
  97.      
  98. NotYet
  99.     move.w    D7,D1                ;update D1 (pass to RadioHiLite)
  100.     jsr        RadioHiLite        ;change radio button selected
  101.     clr.l    -(A7)            ;use standard filter proc function
  102.     pea        ButtonHit(A5)
  103.     _ModalDialog
  104.     cmpi.w    #2,ButtonHit(A5)    ;was select or cancel button hit
  105.     ble        EndDialog            ;yes, so close up dialog
  106.     move.l    D7,D0                ;D0 = id of old radio button
  107.     move.w    ButtonHit(A5),D7    ;D7 = id of new radio button
  108.     bra.s    NotYet                ;loop back for next mouse down
  109.     
  110. EndDialog
  111.     move.l    DialogPort(A5),-(A7)    ;pass address of Dialog Rec
  112.     _CloseDialog                ;close dialog
  113.     
  114.     cmpi.w    #2,ButtonHit(A5)    ;was ok button hit
  115.     blt        Continue            ;yes
  116.     jmp        EventLoop            ;no, go get next event
  117.  
  118. Continue
  119.     subq.w    #3,D7                ;D7 = last radio button hit, so
  120.                                     ;subtract item # for radio
  121.                                     ;button "0"
  122.     move.w    D7,Addr(A5)            ;D7 now equals address selected
  123.     
  124.     jsr        ResetDisk            ;reset SCSI bus
  125.     tst.w    Res(A5)                ;did we succeed
  126.     bne        ToErrorProc            ;no, go handle error
  127.  
  128. ; This next block of code, though the end of this procedure, is
  129. ; an example of how all SCSI commands are done.  You can replace
  130. ; the SCSI command Test Unit Ready with any other SCSI command.
  131. ; The Mode Select and Format Unit commands used in FormatProc 
  132. ; differ only in that data is transfered after the command.
  133.  
  134.  
  135. ; First we get control of the bus and select the target device.
  136.     jsr        HD_Select            ;go get control of bus and
  137.                                     ;select device
  138.     tst.w    Res(A5)                ;did we succeed
  139.     bne        ToErrorProc            ;no, go handle error
  140.  
  141. ; Second, we clear the buffer we use to construct the SCSI
  142. ; command in.
  143.     lea    CommandBuff(A5),A0        ;pass address of buffer in A0
  144.     move.l    #CBuffLen,D0        ;pass buffer size in D0
  145.     jsr        ClearBuff            ;clear buffer
  146.  
  147. ; Third, we construct the command.  This one has no parameters
  148. ; in the CDB (Command Desciption Block), so we only have to move
  149. ; the SCSI OP code into the CDB.
  150.  
  151.     move.b    #TestUReady,CommandBuff(A5)    ;move OP code into byte
  152.                                             ;1 of the CDB
  153.     clr.w    -(A7)                ;clear space for trap result
  154.     pea        CommandBuff(A5)        ;pass address of CDB
  155.     move.w    #CommLenS,-(A7)        ;pass length of command. This is
  156.                                     ;a class 0 SCSI command, so
  157.                                     ;the length is 6 bytes.
  158.  
  159. ; Fourth, we send the command and test if it succeded.
  160.     _SCSICmd                    ;send command to target
  161.     
  162.     move.w    #TestUReady,Last_Cmd(A5)    ;store command id
  163.     move.w    (A7)+,Res(A5)        ;test result, was there an error        
  164.     bne        ToErrorProc            ;yes go to error proc
  165.  
  166. ; Then, we wait for the target device send the Status and
  167. ; Message bytes.  The target device will then release the Mac.
  168.     move.l    #10,D0                ;pass number of ticks to wait
  169.     jsr        HD_Discon            ;proc that handles _SCSIComplete
  170.     tst.w    Res(A5)                ;SCSI Protocal Error?
  171.     bne        ToErrorProc            ;yes, go handle display error
  172.  
  173. ; Lastly, we test the Status byte returned by _SCSIComplete.  
  174. ; This is the SCSI command result code.  It will tell us about
  175. ; the drives condition and if it is ready to be formated.
  176.     move.w    #TestUReady,Last_Cmd(A5)    ;store command id for 
  177.                                             ;error handling proc
  178.     cmp.w    #3,CompStat(A5)        ;is there a Write Fault?
  179.     beq        ToErrorProc            ;yes, go to error handling proc
  180.     cmp.w    #4,CompStat(A5)        ;is the Drive Not Ready?
  181.     beq        ToErrorProc            ;yes, go to error handling proc
  182.     cmp.w    #20,CompStat(A5)    ;is this SCSI command supported?
  183.     beq        ToErrorProc            ;no, go to error handling proc
  184.     
  185.     jmp        EventLoop
  186.  
  187. ToErrorProc
  188.     jmp        ErrorProc
  189.     
  190.     EndProc
  191.  
  192. ; PROC ParamProc
  193. ;
  194. ; We give the user is given dialog box to input parameters used
  195. ; for  formatting drive. We then extract the values from the
  196. ; TextEdit fields and place the hex values in the appropiate
  197. ; global variables.  All values are checked against maximum 
  198. ; values to make sure they are reasonable.
  199.  
  200. ParamProc    PROC    EXPORT
  201.  
  202.     clr.l    -(A7)                ;space for pointer to dialog
  203.     move.w    #ParamRN,-(A7)        ;parameter dialog resource numb.
  204.     pea        DialogBuff(A5)        ;push pointer to dialog storage
  205.     move.l    #-1,-(A7)            ;dialog on top of all windows
  206.     _GetNewDialog
  207.     
  208.     move.l    (A7),DialogPort(A5)    ;save pointer to dialog and 
  209.                                     ;leave copy on stack for 
  210.                                     ;call to _SetPort
  211.     _SetPort
  212.     
  213.     lea        DialogBuff(A5),A4    ;pass address of dialog record
  214.     jsr        DefButton            ;make "OK" button the default
  215. ; Now we set up our dialog box. First two calls to RadioHiLite
  216. ; have D0=0 as a flag for no radio button to unselect
  217. ; Register ussage:
  218. ;    D0    Radio button that was selected, now must be unselected
  219. ;    D1    Radio button that was just clicked on; to be selected
  220. ;    D6    Interleave Radio Button that is currently selected
  221. ;    D7    Step Rate Radio Button that is currently selected
  222.     moveq.l    #3,D6                ;default interleave = 1:1
  223.     moveq.l    #7,D7                ;default step pulse = 3 msec
  224.  
  225. ; High light default interleave and step pulse radio buttons.
  226.     move.w    D6,D1                
  227.     clr.w    D0
  228.     jsr        RadioHiLite
  229.     clr.w    D0
  230.     move.w    D7,D1
  231.     jsr        RadioHiLite
  232.      
  233.      
  234. NotYet
  235.     clr.l    -(A7)            ;use standard filter proc function
  236.     pea        ButtonHit(A5)    ;push address of storage for item#
  237.     _ModalDialog
  238.     move.w    ButtonHit(A5),D1    ;move item number to D1
  239.     cmpi.w    #2,D1                ;was OK or Cancel selected?
  240.     ble        EndDialog            ;yes, go close up dialog
  241.     cmpi.w    #9,D1                ;was text edit item hit
  242.     bgt        NotYet                ;yes, loop back for next event
  243.     cmpi.w    #6,D1            ;was interleave radio button hit
  244.     bgt        StepRate        ;no, must be step rate radio button
  245.  
  246. ; Interleave radio button was selected. Update D6 and select
  247. ; the correct radio button.
  248.     move.w    D6,D0            
  249.     move.w    D1,D6            
  250.     jsr        RadioHiLite
  251.     bra.s    NotYet
  252.     
  253. ; Step rate radio button was selected. Update D7 and select
  254. ; the correct radio button.
  255.     StepRate:
  256.     move.w    D7,D0
  257.     move.w    D1,D7
  258.     jsr        RadioHiLite
  259.     bra        NotYet
  260.             
  261. EndDialog
  262.     
  263.     cmpi.w    #2,ButtonHit(A5)    ;was "Cancel" selected?
  264.     blt        Continue            ;no
  265.     bra        exit                ;yes, so exit
  266. ; "OK" button selected so we can update the global variables
  267. ; that contain the step code and the interleave values.
  268. Continue                        
  269.     subq.w    #2,D6
  270.     move.w    D6,Interleave(A5)
  271.     subq.w    #7,D7
  272.     move.w    D7,StepCode(A5)
  273.  
  274. ; For each of the TextEdit fields we place the address of the
  275. ; global variable in A3, the item # in D0 and the maximum value
  276. ; in D3.  We then call ExtractNumb to get the hex, insure that
  277. ; it is not over the maximum value, and place the hex number in
  278. ; the global variable.
  279.     lea        Heads(A5),A3        ;extract number of heads from 
  280.     move.l    #10,D0                    ;item number 10
  281.     move.l    #MaxHeads,D3
  282.     jsr        ExtractNumb
  283.  
  284.     lea        Cyls(A5),A3            ;extract number of cylinders
  285.     move.l    #11,D0                    ;from item number 11
  286.     move.l    #MaxCylind,D3
  287.     jsr        ExtractNumb
  288.  
  289.     lea        RedWrtCur(A5),A3    ;extract reduced write current
  290.     move.l    #12,D0                    ;cylinder from item #12
  291.     move.l    Cyls(A5),D3
  292.     jsr        ExtractNumb
  293.  
  294.     lea        WrtPreComp(A5),A3    ;extract write precompensation
  295.     move.l    #13,D0                    ;cylinder from item #13
  296.     move.l    Cyls(A5),D3
  297.     jsr        ExtractNumb
  298.     
  299.     
  300. Exit
  301.     move.l    DialogPort(A5),-(A7)    ;pass pointer to Dialog rec
  302.     _CloseDialog                    ;close dialog box
  303.     jmp        EventLoop                ;return to event loop
  304.     EndProc
  305.  
  306. ; PROC EDefectProc
  307. ;
  308. ; Here we ask the user to enter the defects that are listed on
  309. ; the sheet that came with their disk drive.  They can enter as
  310. ; many as 60 defects.  Since our dialog box only has room for 12
  311. ; defects, we ask the user to hit the "More" button if they have
  312. ; additional defects.  We give the user a dialog box when they
  313. ; cannot enter any more defects.
  314. ;
  315. ; Register Ussage:
  316. ;    D0        Index for next item in dialog that is EditText that
  317. ;                we are going to remove a value from
  318. ;    D6        Index for record being input in defect list; index
  319. ;                is byte index of first field in record, not
  320. ;                actual record number
  321. EDefectProc    PROC    EXPORT
  322.  
  323.     clr.l    BadB_Num(A5)        ;clear global for # of defects
  324.  
  325. ; Clear our defect buffer.
  326.     move.l    #MaxBBListLen,D0    ;pass buffer size in D0
  327.     lea        BadB_List(A5),A0    ;pass address in A0
  328.     jsr        ClearBuff            ;go clear buffer
  329.     
  330.  
  331.  
  332. LoopForMore
  333.     clr.l    D6                    ;clear buffer record index
  334.  
  335.     clr.l    -(A7)                ;space for pointer to dialog rec
  336.     move.w    #EDefectsRN,-(A7)    ;Enter Defects Dialog resource #
  337.     pea        DialogBuff(A5)        ;pass pointer to dialog storage
  338.     move.l    #-1,-(A7)            ;make this window on top
  339.     _GetNewDialog                ;get dialog
  340.     
  341.     move.l    (A7),DialogPort(A5)    ;save pointer to dialog and
  342.                                     ;leave a copy on stack for 
  343.                                     ;call to _SetPort 
  344.     _SetPort
  345.     
  346.     lea        DialogBuff(A5),A4    ;pass address of dialog record
  347.     jsr        DefButton            ;outline default button
  348.      
  349.      
  350. NotYet
  351.     clr.l    -(A7)        ;use standard filter proc function
  352.     pea        ButtonHit(A5)    ;place for button hit
  353.     _ModalDialog            ;handle dialog events
  354.     cmpi.w    #3,ButtonHit(A5)            ;is "Cancel" button hit?
  355.     blt        EndDialog        ;no, "More" or "OK" buttons were hit
  356.     bgt        NotYet            ;no, not a button, get another event
  357.  
  358.  
  359. ; User hit "Cancel" button, so clear defect count and return
  360. ; go close dialog box
  361.     clr.l    BadB_Num(A5)    
  362.     bra        exit
  363.  
  364. ; We want to close up the dialog, but first we must extract the
  365. ; defect data that the user has entered.
  366. EndDialog
  367.     move.l    BadB_Num(A5),D6        ;move number of defects into D6
  368.     lsl.l    #4,D6                ;multiply by 16 to get byte 
  369.                                     ;index for first field in
  370.                                     ;next empty record
  371.     lea        BadB_List(A5),A0    ;A0 points 1st byte of buffer
  372.     
  373. AddToBuff
  374.     move.l    #3,D0                ;first item is 4, so put 3 in D0
  375.         
  376. LoopAddBuff
  377. ; First we extract the cylinder number.  We use the ExtractNumb
  378. ; procedure which takes the address for the result in A3, the 
  379. ; maximum value in D3 and the item number in D0.
  380.     
  381.     addq.l    #1,D0                ;increment D0 by 1, next item
  382.     lea        CylBBuff(A0,D6.L),A3
  383.     move.l    #MaxCylind,D3
  384.     jsr        ExtractNumb
  385.     
  386. ; Next we extract the head number
  387.     addq.l    #1,D0
  388.     lea        HeadBBuff(A0,D6.L),A3
  389.     move.l    #MaxHeads,D3
  390.     jsr        ExtractNumb
  391.     
  392. ; Lastly we extract the Bytes From Index value.
  393.     addq.l    #1,D0
  394.     lea        BFIBBuff(A0,D6.L),A3
  395.     move.l    #MaxBFI,D3
  396.     jsr        ExtractNumb
  397.  
  398. ; Test to see if the cylinder number was 0.  If so ignore this
  399. ; record as it was either empty or invalid.  Most controller
  400. ; cards cannot take defects in track 0.
  401.     tst.l    CylBBuff(A0,D6.L)    ;is cylinder value valid
  402.     bne        IncrCounters        ;yes increment counters
  403.  
  404. ; Otherwise, don't increment counters and next record will 
  405. ; overwrite this one which was invalid.
  406.     cmpi.l    #39,D0                ;have we reached the last item
  407.     beq        Exit                ;yes, go close dialog box
  408.     bra        LoopAddBuff            ;no, go extract next record
  409.     
  410. ; Cylinder number is not equal to 0 so this is a valid defect.
  411.  
  412. IncrCounters
  413.     add.l    #BadBRecLen,D6            ;increment buffer index
  414.     cmpi.l    #(MaxBBs*BadBRecLen),D6    ;is our buffer full
  415.     beq.s    Exit                    ;yes, so exit
  416.     cmpi.l    #39,D0
  417.     bne        LoopAddBuff
  418.     
  419. Exit
  420.     
  421.     lsr.l    #4,D6            ;byte count/16 = number of defects    
  422.     move.l    D6,BadB_Num(A5)    ;store defect number in global
  423.     move.l    DialogPort(A5),-(A7)    ;pass pointer to dialog
  424.     _CloseDialog            ;close up dialog
  425.  
  426.     cmpi.l    #60,BadB_Num(A5)    ;are there too many bad blocks
  427.     beq.s    NoMoreAlert            ;yes, go put up alert
  428.     
  429.     cmpi.w    #2,ButtonHit(A5)    ;did user hit "More" button (#2)
  430.     bne        ToEventLoop        ;no, so go to event loop
  431.     bra        LoopForMore        ;yes so put up dialog again
  432.  
  433. ToEventLoop
  434.     jmp        EventLoop
  435.  
  436. NoMoreAlert
  437.     clr.w    -(A7)            ;space for item hit
  438.     move.w    #134,-(A7)        ;get our out of buffer space alert
  439.     clr.l    -(A7)            ;use standard filter proc function
  440.     _CautionAlert            ;use a caution alert
  441.     clr.w    (A7)+            ;discard result
  442.     jmp        EventLoop
  443.     
  444.     EndProc
  445.  
  446. ; PROC FormatProc
  447. ;
  448. ; Formating procedure.  This is where we sent the drive 
  449. ; parameters in a Mode Select command.  We then send the drive
  450. ; defects with the Format Unit command.  And then the drive is
  451. ; ready to use with a driver installing program.
  452. FormatProc    PROC    EXPORT
  453.     IMPORT (HD_Select,HD_Discon,WriteDisk):CODE
  454.  
  455. ; First we put up a dialog box to make sure the user wants to 
  456. ; format the drive.
  457.  
  458. ; Make String buffer #1, 1 character long.  Then move the hex 
  459. ; value in the low order byte of Addr (the SCSI address of the
  460. ; target device) into the string buffer and convert it to ascii.
  461.     move.b    #1,StrBuff1(A5)    
  462.     move.b    1+Addr(A5),1+StrBuff1(A5)    
  463.     add.b    #$30,1+StrBuff1(A5)    
  464.     
  465.     clr.b    StrBuff2(A5)    ;clear all the other string buffers
  466.     clr.b    StrBuff3(A5)
  467.     clr.b    StrBuff4(A5)
  468.     pea        StrBuff1(A5)
  469.     pea        StrBuff2(A5)
  470.     pea        StrBuff3(A5)
  471.     pea        StrBuff4(A5)
  472.     _ParamText                ;substitute String buffer 1 for "^0"
  473.     
  474.     clr.w    -(A7)        ;space for item hit
  475.     move.w    #132,-(A7)    ;get format alert dialog box
  476.     clr.l    -(A7)        ;use standard filter proc function
  477.     _CautionAlert
  478.     cmpi.w    #1,(A7)+    ;did user hit cancel?
  479.     bne        Exit        ;yes, so exit
  480.  
  481. ; User wants to Zap Drive, so let 'em have it!    First we 
  482. ; construct a data block to place parameters that we will send
  483. ; with the Mode Select command.
  484. ZapDrive
  485.  
  486. ; First we clear the data buffer
  487.     lea        ParamBuff(A5),A0    ;pass address of buffer
  488.     move.l    #ParamBuffLen,D0    ;pass length of buffer
  489.     jsr        ClearBuff            ;clear buffer
  490.     
  491.     clr.l    D0                    ;clear D0, used for scratch
  492. ; Header:
  493.     move.b    #8,$3(A0)            ;3rd byte = size of descriptor
  494.                                     ;list
  495.  
  496. ; Descriptor List:
  497.     move.b    #2,$A(A0)            ;high byte of sector size ($200)
  498.     
  499. ; Drive Parameter List:
  500.     move.b    #1,$C(A0)            ;List Format Code: (1 = soft
  501.                                     ;sectored drives, 2= hard
  502.                                     ;sectored drives or 
  503.                                     ;removable media drives)
  504.     
  505. ; Place word value of cylinder count into buffer.  We must do 
  506. ; this as two bytes because the wored in the output buffer is
  507. ; at an odd address
  508.     move.w    2+Cyls(A5),D0
  509.  
  510.     move.b    D0,$E(A0)        ;make sure $E(A0) has LSB
  511.     lsr.l    #8,D0            ;now move in high byte of word
  512.     move.b    D0,$D(A0)
  513.  
  514. ; Move byte value of head count into buffer.
  515.     move.b    3+Heads(A5),$F(A0)
  516.     
  517. ; Move word value of Reduced Write Current Cylinder into buffer.
  518.     move.w    2+RedWrtCur(A5),$10(A0)
  519.     
  520. ; Move word value of Write Precompensation Cylinder into buffer.
  521.     move.w    2+WrtPreComp(A5),$12(A0)
  522.     
  523. ; Move byte value of Step Pulse Code into Buffer.
  524.     move.b    1+stepcode(A5),$15(A0)
  525.     
  526. ; Now we send the Mode Select Command and the parameter buffer.
  527.     jsr        HD_Select        ;get SCSI bus and select drive
  528.     tst.w    Res(A5)            ;did we succeed?
  529.     bne        ToErrorProc        ;no, so go to error handling proc
  530.         
  531. ; Clear command buffer and construct command.
  532.     lea    CommandBuff(A5),A0    ;pass address of buffer
  533.     move.l    #CBuffLen,D0    ;pass length of buffer
  534.     jsr        ClearBuff        ;clear command buffer
  535.     
  536.     move.b    #ModeSelect,(A0)    ;move SCSI OP Code into byte #0
  537.     
  538.     move.b    #ModeSelBytesOut,4(A0)    ;move # of bytes to transfer
  539.                                         ;into byte #4
  540.     
  541.     clr.w    -(A7)            ;space for trap error code
  542.     move.l    A0,-(A7)        ;pass address of command buffer
  543.     move.w    #CommLenS,-(A7)    ;pass length of CDB (Command Data
  544.                                 ;Block), class 0 command, so it
  545.                                 ;is 6 bytes long
  546.     _SCSICmd                ;send command
  547.     
  548.     move.w    #ModeSelect,Last_Cmd(A5)    ;store command id 
  549.         
  550.     move.w    (A7)+,Res(A5)    ;did command work?
  551.     bne        ToErrorProc        ;no, go to error handling proc
  552.  
  553. ; Now we clear the pseudo program buffer and call the procedure
  554. ; WriteDisk to send the data to the controller card.
  555.     lea        PseudoProg(A5),A0    ;pass address of buffer
  556.     move.l    #PProgLen,D0        ;pass size of buffer
  557.     jsr        ClearBuff            ;clear buffer
  558.     
  559.     lea        ParamBuff(A5),A1    ;pass address of data buffer
  560.     move.l    #ModeSelBytesOut,D0    ;pass # of bytes to transfer
  561.     jsr        WriteDisk            ;send data
  562.  
  563.     move.l    #10,D0                ;pass number of ticks to wait
  564.     jsr        HD_Discon
  565.     tst.w    Res(A5)                ;SCSI Protocal Error?
  566.     bne        ToErrorProc
  567.     move.w    #ModeSelect,Last_Cmd(A5)
  568.     cmp.w    #$4,CompStat(A5)    ;is the Drive Not Ready?
  569.     beq        ToErrorProc            ;yes, go to error handling proc
  570.     cmp.w    #$24,CompStat(A5)    ;Was a bad parameter passed to
  571.                                     ;the controller?
  572.     beq        ToErrorProc            ;yes, go to error handling proc
  573.     
  574.     jsr        HD_Select            ;go get control of bus and 
  575.                                     ;select device
  576.     tst.w    Res(A5)                ;did we succeed
  577.     bne        ToErrorProc            ;no, go to error proc
  578.  
  579. ; Next, clear the buffer where we will assemble the CDB (Command
  580. ; Data Block).
  581.     lea        CommandBuff(A5),A0    ;pass address of buffer
  582.     move.l    #CBuffLen,D0        ;pass size of buffer
  583.     jsr        ClearBuff            ;clear buffer
  584.  
  585.     
  586.     move.b    #FormatUnit,(A0)    ;move op code into first byte
  587.     move.b    1+Interleave(A5),4(A0)    ;move byte value of inter
  588.                                         ;leave into byte 4
  589.     
  590.     tst.l    BadB_num(A5)        ;see if there are disk defects
  591.     beq        NoDefects            ;no, skip ahead
  592.     add.b    #$1C,1(A0)            ;place flags to tell controller
  593.                                     ;that defects are coming
  594. ; Call OutBuff to format defects so they can be read by
  595. ; controller card.
  596.     jsr        OutBuff                
  597.     
  598. NoDefects
  599.     clr.w    -(A7)                ;space for trap error code
  600.     move.l    A0,-(A7)            ;pass address of CDB
  601.     move.w    #CommLenS,-(A7)        ;class 0 command so pass length
  602.                                     ;of 6 bytes
  603.     _SCSICmd                    ;send command
  604.     
  605.     move.w    #FormatUnit,Last_Cmd(A5)    ;store command id
  606.         
  607.     move.w    (A7)+,Res(A5)        ;did _SCSICmd produce an error
  608.     bne        ToErrorProc            ;yes, go to error handling proc
  609.     
  610. ; If we are sending any info on disk defects, prepare buffer for
  611. ; pseudo program and pass count bytes and address to sending
  612. ; procedure.
  613.     tst.l    BadB_num(A5)        ;are we sending any defect data?
  614.     beq        NoPseudoProg        ;no, skip the next section
  615.  
  616. ; Clear pseudo program buffer.    
  617.     lea        PseudoProg(A5),A0    ;pass address of buffer
  618.     move.l    #PProgLen,D0        ;pass length of buffer
  619.     jsr        ClearBuff            ;clear buffer
  620.  
  621. ; Pass address of data, and number of bytes to be transfered. A0
  622. ; still contains the address of the pseudo program buffer.
  623.     lea        BadB_Out(A5),A1
  624.     move.l    BadB_Num(A5),D0        ;move number of defects to D0
  625.     lsl.l    #3,D0                ;multiply by 8 (8 bytes/defect)
  626.     addq.l    #4,D0                ;add 4 bytes for header
  627.     jsr        WriteDisk            ;send info on defects
  628.  
  629. NoPseudoProg
  630.     move.l    #MaxTicks,D0        ;pass number of ticks to wait
  631.     jsr        HD_Discon
  632.     tst.w    Res(A5)                ;SCSI Protocal Error?
  633.     bne        ToErrorProc            ;yes, go to error handling proc
  634.  
  635. ; Test Status byte from SCSI command to see if we passed a bad
  636. ; parameter or if there is a defect on track 0.
  637.     move.w    #FormatUnit,Last_Cmd(A5)    ;update command id for
  638.                                             ;error handling proc
  639.     cmp.w    #$24,CompStat(A5)    ;Was a bad parameter passed to 
  640.                                     ;the controller?
  641.     beq        ToErrorProc            ;yes, go to error proc
  642.     jmp        EventLoop    
  643.  
  644. Exit
  645.     jmp        EventLoop
  646.     
  647. ToErrorProc
  648.     jmp        ErrorProc
  649.     
  650.     EndProc
  651.  
  652. ; PROC ResetProc
  653. ;
  654. ; This procedure is called from the menu handling routine.  It
  655. ; acts as glue between the menu handling code and the reset 
  656. ; subroutine and allows us to use the reset subroutine elsewhere
  657. ; (like in SelAddrProc).
  658. ResetProc    PROC    EXPORT
  659.     IMPORT    (ResetDisk):CODE
  660.     
  661.     jsr        ResetDisk        ;go reset SCSI bus
  662.     tst.w    Res(A5)            ;test result
  663.     bne        ToErrorProc        ;if error go to error handling proc
  664.     jmp        EventLoop        ;else return to event loop
  665. ToErrorProc
  666.     jmp        ErrorProc
  667.     EndProc
  668.  
  669. ; PROC WriteDisk
  670. ;
  671. ; Procedure wor transfering data to the controller. This 
  672. ; routine uses a pseudo program which contains a simple loop of
  673. ; three instructions. This transfer could have been accomplished
  674. ; using only the first and the last instruction if we had put 
  675. ; the transfer count that is passed in D0 into the second 
  676. ; parameter of the first command. It would look exactly the 
  677. ; same if it were being used for a read, except the _SCSIWrite 
  678. ; trap would be replaced with _SCSIRead. Refer to IM volume IV 
  679. ; for info on the Pseudo instructions. Note each instruction is 
  680. ; a  word followed by two longword parameters.  SCSTOP must be 
  681. ; the last instruction. Address of pseudo buffer is passed in 
  682. ; A0.  Address of p_buff is passed in A1. Transfer count is 
  683. ; passed in D0.
  684. WriteDisk    PROC    ENTRY
  685.     movem.l    D0-D2/A0-A1,-(SP)    ;save registers
  686.  
  687. ; First command    moves bytes to given address
  688.     move.w    #SCINC,(A0)        
  689.     move.l    A1,2(A0)        ;address to be moved to or from
  690.     move.l    #1,6(A0)        ;transfer count in bytes
  691.  
  692. ; Second command is loop    
  693.     move.w    #SCLOOP,10(A0)    
  694.     move.l    #-10,12(A0)        ;rel addr
  695.     move.l    d0,16(A0)        ;loop count
  696.  
  697. ; Third command = stop, no parameters    
  698.     move.w    #SCSTOP,20(A0)    
  699.     
  700.     clr.w    -(SP)            ;space for trap result code (OSErr)
  701.     move.l    A0,-(SP)        ;address of pseudo program
  702.     
  703.     _SCSIWrite
  704.     move.w    (SP)+,Res(A5)    ;store result
  705.     move.w    #Write,Last_Cmd(A5)        ;store code for type of SCSI
  706.                                         ;command
  707.     
  708.     movem.l    (SP)+,D0-D2/A0-A1    ;restore registers
  709.     rts
  710.     ENDPROC
  711.     
  712. ; PROC HD_Select
  713. ;
  714. ; HD_Select tries to get control of the SCSI bus.  If it does,
  715. ; it then selects the device whose address is in Addr(A5).
  716.  
  717. HD_Select        PROC    ENTRY
  718.     IMPORT    CountOff:CODE
  719.     movem.l    D0-D2/A0-A1,-(A7)    ;save regs on stack
  720.     
  721.     clr.w    -(A7)                ;space for result code
  722.     _SCSIGet                    ;reserve the bus for our use
  723.     
  724.     move.w    (A7)+,Res(A5)        ;store result code
  725.     beq.s    ok                ;go to ok2 if we succeeded
  726.     move.w    #Get,Last_Cmd(A5)    ;else, store the last command
  727.     bra.s    exit                ;and return
  728.         
  729. ok
  730.     clr.w    -(A7)                ;space for result code
  731.     move.w    Addr(A5),-(A7)        ;load SCSI address of hard disk
  732.     _SCSISelect                    ;select device
  733.     
  734.     move.w    (A7)+,Res(A5)        ;store result code
  735.     move.w    #Select,Last_Cmd(A5)    ;store last command
  736.  
  737. exit
  738.     movem.l    (A7)+,D0-D2/A0-A1    ;restore registers
  739.     rts
  740.     ENDPROC
  741.  
  742.  
  743. ; PROC HD_Discon
  744. ;
  745. ; Here we complete a SCSI command.  We tell the Mac how long to
  746. ; wait for the target device on the SCSI bus to signal that the
  747. ; command has completed.  This procedure receives the number of
  748. ; ticks to wait in D0.
  749. HD_Discon    PROC    ENTRY
  750.     
  751.         movem.l    D0-D2/A0-A1,-(A7)    ;save regs on stack
  752.         
  753.         clr.w    CompStat(A5)
  754.         clr.w    CompMsg(A5)
  755.         
  756.         clr.w    -(A7)                ;space for result code
  757.         pea        CompStat(A5)        ;_SCSIComplete Status
  758.         pea        CompMsg(A5)            ;_SCSIComplete Message
  759.         move.l    D0,-(A7)            ;number of ticks to wait for
  760.                                         ;completion of the last
  761.                                          ;SCSI command
  762.         _SCSIComplete                                
  763.         move.w    (A7)+,Res(A5)    ;store result code
  764.         move.w    #Complete,Last_Cmd(A5)    ;store last command 
  765.         movem.l    (A7)+,D0-D2/A0-A1    ;restore registers
  766.         rts
  767.         ENDPROC
  768.  
  769. ; PROC InitGlobals
  770. ;
  771. ; Initialize the globals used to store information about the 
  772. ; hard disk.  Set all values to zero
  773. InitGlobals        PROC    EXPORT
  774.         
  775.         clr.w    Heads(A5)
  776.         clr.w    Cyls(A5)
  777.         clr.w    WrtPreComp(A5)
  778.         clr.w    RedWrtCur(A5)
  779.         clr.w    Interleave(A5)
  780.         clr.w    StepCode(A5)
  781.         clr.l    Addr(A5)
  782.  
  783.         clr.l    BadB_Num(A5)
  784.         
  785.         rts
  786.         ENDPROC
  787.  
  788. ; PROC ResetDisk
  789. ;
  790. ; This procedure resets the SCSI bus.  It has a one second delay
  791. ; after the reset because the CDC Wren III drives take more than
  792. ; 3/4 of a second to completely reset.  Other drives may need 
  793. ; longer delays after the reset.
  794. ResetDisk    PROC    EXPORT
  795.  
  796.     movem.l    D0-D2/A0-A1,-(A7)    ;save the registers
  797.     clr.w    -(A7)                ;space for result code
  798.     _SCSIReset                    ;reset the bus
  799.     move.w    (A7)+,Res(A5)        ;store results
  800.     beq.s    ok1                    ;go to ok1 if we succeeded
  801.     move.w    #Reset,Last_Cmd(A5)    ;else command code for error Msg
  802.     rts
  803.     
  804. ok1
  805.     move.l    #60,D0                ;D0 = number of ticks to wait
  806.     jsr        CountOff            ;jst to delay routine
  807.     
  808.     movem.l    (A7)+,D0-D2/A0-A1    ;restore the registers
  809.     rts
  810.     ENDPROC
  811.     
  812.     END